package test 
{
	import adobe.utils.CustomActions;
	import draw.DrawTool;
	import flash.display.DisplayObject;
	import flash.display.Graphics;
	import flash.display.InteractiveObject;
	import flash.display.Shape;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Bezier;
	import flash.geom.Point;
	import flash.net.FileReference;
	import flash.text.TextField;
	import gui.buttons.LabelButton;
	import simple3D.core.ShapeData;
	import simple3D.core.ShapeFactory;
	import utils.ImageChooser;
	import utils.Logger;
	/**
	 * ...
	 * @author Dmitriy Gaiduk
	 */
	public class TestBezier extends Sprite
	{
		private var _shape:Shape;
		
		private var _startPoint:Sprite;
		private var _anchorPoint:Sprite;
		private var _controlPoint:Sprite;
		
		
		private var _currentSelected:Sprite = null;
		
		private var _imageChooser:ImageChooser;
		private var _imageHolder:Sprite;
		public function TestBezier() 
		{
			addEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
		}
		
		private function handleAddedToStage(e:Event):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, handleAddedToStage);
			//initTest();
			initDrawTest();
		}
		
		private function initDrawTest():void 
		{
			_imageHolder = new Sprite();
			addChild(_imageHolder);
			
			var lines:Array = [[0, 460, 600, 460, 300, 540], [300, 0, 300, 500]];
			var edge:Array = 
			//[[ 720, 0], [ 720, 300], [ 0, 300], [ 0, 165], [ 72, 87, 16, 107, 195, 0 , 163, 92], [ 720, 0]];
			[[0, 0], [300, 0], [ 300, 720], [165, 720], [87, 648, 107, 704, 0, 525 , 92 , 557], [0, 0]];
			_imageHolder.x = 100;
			_imageHolder.y = 100;
			
			_imageHolder.graphics.lineStyle(2, 0x000000);
			//DrawTool.drawEdge(_imageHolder.graphics, reversePointsByAxis(edge, 0));
			DrawTool.drawLines(_imageHolder.graphics, lines);
		}
		
		private function reversePointsByAxis(edge:Array, axis:int):Array
		{
			log("Reverse");
			var maxValue:Number = 0;
			var minValue:Number = Number.MAX_VALUE;
			var points:Array = [];
			var pointsXY:Array;
			var pointsXYAdjusted:Array;
			var i:int;
			var j:int;
			for (i = 0; i < edge.length; i++ )
			{
				pointsXY = edge[i];
				for (j = 0; j < pointsXY.length; j += 2 )
				{
					maxValue = Math.max(maxValue, pointsXY[j + axis]);
					minValue = Math.min(minValue, pointsXY[j + axis]);
				}
			}
			
			var shapeSizeByAxis:Number = maxValue - minValue;
			
			for (i = 0; i < edge.length; i++ )
			{
				pointsXY = edge[i];
				pointsXYAdjusted = [];
				
				for (j = 0; j < pointsXY.length; j += 2 )
				{
					if (axis == 0)
					{
						pointsXYAdjusted.push(maxValue - pointsXY[j] + minValue);
						pointsXYAdjusted.push(pointsXY[j + 1]);
					}else
					{
						pointsXYAdjusted.push(pointsXY[j]);
						pointsXYAdjusted.push(maxValue - pointsXY[j + 1] + minValue);
					}
				}
				
				points.push(pointsXYAdjusted);
			}
			
			log("max: " + maxValue);
			return points;
		}
		
		private function initTest():void 
		{
			_imageHolder = new Sprite();
			addChild(_imageHolder);
			
			var addPicBtn:LabelButton = new LabelButton(this, 200, 10);
			addPicBtn.label = "Add picture";
			addPicBtn.width = 100;
			addPicBtn.width = 50;
			addPicBtn.addEventListener(MouseEvent.CLICK, handleAddImgClick);
			
			_shape = new Shape();
			_shape.x = 0;
			_shape.y = 0;
			addChild(_shape);
			
			_imageHolder.graphics.lineStyle(1, 0x000000);
			//var edge:Array = [[0, 0], [300, 0], [ 300, 525], [ 0, 720 , 150 , 500], [0, 0]];
			var edge:Array = 
			[[0, 0], [300, 0], [ 300, 720], [165, 720], [87, 648, 107, 704, 0, 525 , 92 , 557], [0, 0]];
			//[[0, 0], [0, 300], [200, 300, 100, 380, 400, 300, 300, 220], [400, 0]];
			//[[0, 300], [200, 300, 100, 380]];
			//[ [165, 720], [87, 648, 107, 704, 0, 525 , 92 , 557]];
			//DrawTool.drawEdge(_imageHolder.graphics, edge);
			//drawEdge(_imageHolder.graphics, edge);
			testShapeData(_imageHolder.graphics, edge);
			
			/*_shape.graphics.lineStyle(1, 0x00FF00);
			// x -->
			_shape.graphics.moveTo(0, 0);
			_shape.graphics.lineTo(100, 0);
			// y -->
			_shape.graphics.moveTo(0, 0);
			_shape.graphics.lineTo(0, 100);*/
			
			
			/*	first point		
				start x: 165.05 y: 0.95
				anchor x: 89.15 y: 69.85
				control x: 107.15 y: 16.3 // throw point
				*/
				
			/* second
			 * 	
				start x: 86.85 y: 71.9
				anchor x: 0.4 y: 197.15 
				control x: 91.9 y: 163.15 // 
			*/
				
				
			_startPoint = new Sprite();
			initPoint(_startPoint, 0x66CC00);
			_startPoint.x = 86.85;
			_startPoint.y = 71.9;	
			addChild(_startPoint);
			
			_controlPoint = new Sprite();
			initPoint(_controlPoint, 0xFF9900);
			_controlPoint.x = 91.9;
			_controlPoint.y = 163.15;
			addChild(_controlPoint);
			
			_anchorPoint = new Sprite();
			initPoint(_anchorPoint, 0x3399CC);
			_anchorPoint.x = 0.4;
			_anchorPoint.y = 197.15;
			addChild(_anchorPoint);
			
			
			stage.addEventListener(MouseEvent.MOUSE_UP,  handleMouseUp);
			addEventListener(Event.ENTER_FRAME, handleEnterFrame);
			
		}
		
		private function drawGrid(gr:Graphics, shapeData:ShapeData):void
		{
			gr.moveTo(shapeData.points[shapeData.indices[0]].x, shapeData.points[shapeData.indices[0]].y)
			for (var i:int = 0; i < shapeData.indices.length; i+=3)
			{
				gr.lineTo(shapeData.points[shapeData.indices[i]].x, shapeData.points[shapeData.indices[i]].y);
				gr.lineTo(shapeData.points[shapeData.indices[i+2]].x, shapeData.points[shapeData.indices[i+2]].y);
				gr.lineTo(shapeData.points[shapeData.indices[i+3]].x, shapeData.points[shapeData.indices[i+3]].y);
			}
		}
		
		
		private function drawEdge(gr:Graphics, _edgePoints:Array):void
		{
			var points:Vector.<Number>;
			var pointsXY:Array;
			var prevXY:Array;
			prevXY = _edgePoints[0];
			gr.moveTo(prevXY[0], prevXY[1]);
			for (var i:int = 1; i < _edgePoints.length; i++ )
			{
				pointsXY = _edgePoints[i];
				
				if (pointsXY.length == 2)
				{
					gr.lineTo(pointsXY[0], pointsXY[1]);
					prevXY = _edgePoints[i];
					addLabel(pointsXY[0], pointsXY[1], i.toString() + " Line");
				}else if (pointsXY.length > 2)
				{
					points = new Vector.<Number>();
					var k:int = 0;
					// make points arr : 3 pair points
					var startXY:Array = [prevXY[0], prevXY[1]];
					log("prev x: " + prevXY[0] + " y: " +  prevXY[1]);
					while (k < pointsXY.length)
					{
						/*log("draw bezier points: " + pointsXY + " prev: " + prevXY);
						log("start: " + prevXY[0] + ": " + prevXY[1]);
						log("control: " + pointsXY[k+2] + ": " +  pointsXY[k+3]);
						log("end: " +pointsXY[k] + ": " + pointsXY[k + 1]);
						*/
						//points = new Vector.<Number>();
						//addLabel(prevXY[k], prevXY[k+1], i.toString() + ": " + k + " st");
						//addLabel(pointsXY[k+2], pointsXY[k+3], i.toString() + ": " + k + " contr");
						//addLabel(pointsXY[k], pointsXY[k+1], i.toString() + ": " + k + " end");
						// pair points {x,y} start, control, end
						points.push(prevXY[0], prevXY[1], pointsXY[k+2], pointsXY[k+3], pointsXY[k], pointsXY[k+1]);
						
						prevXY = [pointsXY[k],  pointsXY[k + 1]];
						//drawBezier(gr, points);
						k += 4;
					}
					k -= 4; // setup current k
					drawBezierMulti(gr, points);
					//drawBezier(gr, points);
				}else
				{
					throw Error("Wrong shape data");
				}
			}
		}
		
		private function testShapeData(gr:Graphics, _edgePoints:Array):void
		{
			var points:Vector.<Number>;
			var pointsXY:Array;
			var prevXY:Array;
			prevXY = _edgePoints[0];
			gr.moveTo(prevXY[0], prevXY[1]);
			for (var i:int = 1; i < _edgePoints.length; i++ )
			{
				gr.lineStyle(1, 0x00FF00);
				pointsXY = _edgePoints[i];
				
				if (pointsXY.length == 2)
				{
					gr.lineTo(pointsXY[0], pointsXY[1]);
					prevXY = _edgePoints[i];
					addLabel(pointsXY[0], pointsXY[1], i.toString() + " Line");
				}else if (pointsXY.length > 2)
				{
					points = new Vector.<Number>();
					var k:int = 0;
					// make points arr : 3 pair points
					var startXY:Array = [prevXY[0], prevXY[1]];
					while (k < pointsXY.length)
					{
						points.push(prevXY[0], prevXY[1], pointsXY[k+2], pointsXY[k+3], pointsXY[k], pointsXY[k+1]);
						
						prevXY = [pointsXY[k],  pointsXY[k + 1]];
						k += 4;
					}
					k -= 4; // setup current k
					drawBezierMulti(gr, points);
					
					//drawBezier(gr, points);
				}else
				{
					throw Error("Wrong shape data");
				}
			}
			
			gr.lineStyle(1, 0x000000);
			var shapeData:ShapeData = ShapeFactory.getBezierDataMulti(points, 100);
			gr.moveTo(shapeData.points[shapeData.indices[0]].x, shapeData.points[shapeData.indices[0]].y)
			for (i = 0; i < shapeData.indices.length; i+=3)
			{
				gr.lineTo(shapeData.points[shapeData.indices[i]].x, shapeData.points[shapeData.indices[i]].z);
				gr.lineTo(shapeData.points[shapeData.indices[i+1]].x, shapeData.points[shapeData.indices[i+1]].z);
				gr.lineTo(shapeData.points[shapeData.indices[i+2]].x, shapeData.points[shapeData.indices[i+2]].z);
			}
		}
		
		
		private function addLabel(posX:Number, posY:Number, txt:String):void
		{
			var shape:Shape = new Shape();
			shape.graphics.lineStyle(1, 0x000000);
			shape.graphics.beginFill(0xFF0000, 0.5);
			shape.graphics.drawCircle(0, 0, 5);
			shape.graphics.endFill();
			
			shape.x = posX;
			shape.y = posY;
			_imageHolder.addChild(shape);
			
			var tf:TextField = new TextField();
			tf.text = txt;
			tf.x = posX;
			tf.y = posY;
			
			_imageHolder.addChild(tf);
		}
		
		private function drawBezier(gr:Graphics, points:Vector.<Number>):void
		{
			var k: int = 0;
			while (k < points.length)
			{
				log("draw bezier points: " + points);
				log("start: " + points[k] + ": " + points[k+1]);
				log("control: " + points[k+2] + ": " +  points[k+3]);
				log("end: " +points[k+4] + ": " + points[k + 5]);
				// начальная точка, она же конечная точка предыдущей кривой для количества кривых >1
				var start:Point = new Point(points[k], points[k + 1]); 
				// точка управления, куда стремиться искривление
				var control:Point = new Point(points[k + 2], points[k + 3]); 
				// конечная
				var end:Point = new Point(points[k + 4], points[k + 5]); 
				gr.moveTo(start.x, start.y);
				gr.curveTo(control.x, control.y, end.x, end.y);
				k += 6; // 3 x pair point {x,y}
			}
		}
		
		private function drawBezierMulti(gr:Graphics, points:Vector.<Number>):void
		{
			var k:int = 0;
				// кол-во сегментов по оси Y для каждой кривой
			var segmentCountPerLineH:int = 2; // segments in Y axis for one curve
			// кол-во сегментов по оси X для каждой кривой
			var segmentCountPerLineW:int = 10; // segments in X axis for one curve
			gr.lineStyle(1, 0xFF0000);
			while (k < points.length)
			{
				// начальная точка, она же конечная точка предыдущей кривой для количества кривых >1
				var start:Point = new Point(points[k], points[k + 1]); 
				
				// точка управления, куда стремиться искривление
				var control:Point = new Point(points[k + 2], points[k + 3]); 
				// конечная
				var end:Point = new Point(points[k+4], points[k+5]); 
				
				gr.moveTo(start.x, start.y);
				//addLabel(start.x, start.y, "start: " + start.x + " " + start.y);
				var bezier:Bezier = new Bezier(start, control, end); // строим модель кривой, без представления
				// height of segment
				var segmentH:Number = height / segmentCountPerLineH;
				var bezierT:Number; //0..1
				var bezierStep:Number = 1 / segmentCountPerLineW;
				//define bezier points
				var bezierPoint:Point;
				
				for (var h:int = 0; h <= segmentCountPerLineH; h++)
				{
					gr.moveTo(start.x, start.y);
					var ti:int = k==0? 0 : 1;
					for (ti; ti <= segmentCountPerLineW; ti++)
					{
						bezierT = bezierStep * ti;
						if (ti == segmentCountPerLineW)
						{
							bezierT = 1;
						}
						
						bezierPoint = bezier.getPoint(bezierT);
						//log("t: " + bezierT + " p x: " + bezierPoint.x + " y: " + bezierPoint.y);
						gr.lineTo(bezierPoint.x, bezierPoint.y);
					}
				}
				
				gr.lineStyle(1, 0x00FF00);
				k += 6; // 3 x pair point {x,y}
			}
				addLabel(bezierPoint.x, bezierPoint.y, "end: " + bezierPoint.x + " " + bezierPoint.y);
		}
		
		private function handleAddImgClick(e:MouseEvent):void 
		{
			if (_imageChooser == null)
			{
				_imageChooser = new ImageChooser();
			}
			_imageChooser.addEventListener(Event.COMPLETE, handleImageLoadComplete);
			_imageChooser.Browse();
		}
		
		private function handleImageLoadComplete(e:Event):void 
		{
			var image:DisplayObject = _imageChooser.content as DisplayObject;
			if (image != null)
			{
				_imageHolder.addChild(image);
			}
		}
		
		
		
		private function handleEnterFrame(e:Event):void 
		{
			if (_currentSelected != null)
			{
				_shape.graphics.clear();
				_shape.graphics.lineStyle(1, 0x000000);
				_shape.graphics.moveTo(_startPoint.x, _startPoint.y);
				_shape.graphics.curveTo(_controlPoint.x, _controlPoint.y, _anchorPoint.x, _anchorPoint.y);
			}
		}
		
		private function initPoint(obj:Sprite, color:uint):void
		{
			obj.buttonMode = true;
			drawCircle(obj.graphics, color);
			obj.addEventListener(MouseEvent.MOUSE_DOWN,  handleMouseDown);
		}
		
		private function handleMouseUp(e:MouseEvent):void 
		{
			if (_currentSelected != null)
			{
				_currentSelected.stopDrag();
			}
			
			trace("===========================");
			printPos(_startPoint, "start");
			printPos(_anchorPoint, "anchor");
			printPos(_controlPoint, "control");
			
			
		}
		
		private function printPos(obj:DisplayObject, title:String):void
		{
			trace(title + " x: " + obj.x + " y: " + obj.y);
		}
		
		private function handleMouseDown(e:MouseEvent):void 
		{
			_currentSelected = e.currentTarget as Sprite;
			if (_currentSelected != null)
			{
				_currentSelected.startDrag();
			}
		}
		
		private function drawCircle(gr:Graphics, color:uint):void
		{
			gr.lineStyle(1, 0x000000);
			gr.beginFill(color, 0.5);
			gr.drawCircle(0, 0, 10);
			gr.endFill();
			
			gr.beginFill(0x000000, 1);
			gr.drawCircle(0, 0, 1);
			gr.endFill();
		}
		
		private function log(msg:String):void
		{
			Logger.log(this, msg);
		}
		
	}

}